home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / libgimp / gimpexport.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-24  |  20.2 KB  |  716 lines

  1. /* LIBGIMP - The GIMP Library
  2.  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
  3.  *
  4.  * gimpexport.c
  5.  * Copyright (C) 1999-2000 Sven Neumann <sven@gimp.org>
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2 of the License, or (at your option) any later version.
  11.  *
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Library General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the
  19.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20.  * Boston, MA 02111-1307, USA.
  21.  */                             
  22.  
  23. #include "config.h"
  24.  
  25. #include <gtk/gtk.h>
  26.  
  27. #include "gimp.h"
  28. #include "gimpui.h"
  29.  
  30. #include "libgimp-intl.h"
  31.  
  32.  
  33. typedef void (* ExportFunc) (gint32  imageID,
  34.                  gint32 *drawable_ID);
  35.  
  36.  
  37. /* the export action structure */
  38. typedef struct 
  39. {
  40.   ExportFunc  default_action;
  41.   ExportFunc  alt_action;
  42.   gchar      *reason;
  43.   gchar      *possibilities[2];
  44.   gint        choice;
  45. } ExportAction;
  46.  
  47.  
  48. /* the functions that do the actual export */
  49.  
  50. static void
  51. export_merge (gint32  image_ID,
  52.           gint32 *drawable_ID)
  53. {
  54.   gint32  nlayers;
  55.   gint32  nvisible = 0;
  56.   gint32  i;
  57.   gint32 *layers;
  58.   gint32  merged;
  59.   gint32  transp;
  60.  
  61.   layers = gimp_image_get_layers (image_ID, &nlayers);
  62.   for (i = 0; i < nlayers; i++)
  63.     {
  64.       if (gimp_drawable_visible (layers[i]))
  65.     nvisible++;
  66.     }
  67.  
  68.   if (nvisible <= 1)
  69.     {
  70.       /* if there is only one (or zero) visible layer, add a new transparent
  71.      layer that has the same size as the canvas.  The merge that follows
  72.      will ensure that the offset, opacity and size are correct */
  73.       transp = gimp_layer_new (image_ID, "-",
  74.                    gimp_image_width (image_ID),
  75.                    gimp_image_height (image_ID),
  76.                    gimp_drawable_type (*drawable_ID) | 1,
  77.                    100.0, GIMP_NORMAL_MODE);
  78.       gimp_image_add_layer (image_ID, transp, 1);
  79.       gimp_selection_none (image_ID);
  80.       gimp_edit_clear (transp);
  81.       nvisible++;
  82.     }
  83.  
  84.   if (nvisible > 1)
  85.     {
  86.       g_free (layers);
  87.       merged = gimp_image_merge_visible_layers (image_ID, GIMP_CLIP_TO_IMAGE);
  88.  
  89.       if (merged != -1)
  90.     *drawable_ID = merged;
  91.       else
  92.     return;  /* shouldn't happen */
  93.       
  94.       layers = gimp_image_get_layers (image_ID, &nlayers);
  95.     }    
  96.   
  97.   /* remove any remaining (invisible) layers */ 
  98.   for (i = 0; i < nlayers; i++)
  99.     {
  100.       if (layers[i] != *drawable_ID)
  101.     gimp_image_remove_layer (image_ID, layers[i]);
  102.     }
  103.   g_free (layers);  
  104. }
  105.  
  106. static void
  107. export_flatten (gint32  image_ID,
  108.         gint32 *drawable_ID)
  109. {  
  110.   gint32 flattened;
  111.   
  112.   flattened = gimp_image_flatten (image_ID);
  113.  
  114.   if (flattened != -1)
  115.     *drawable_ID = flattened;
  116. }
  117.  
  118. static void
  119. export_convert_rgb (gint32  image_ID,
  120.             gint32 *drawable_ID)
  121. {  
  122.   gimp_image_convert_rgb (image_ID);
  123. }
  124.  
  125. static void
  126. export_convert_grayscale (gint32  image_ID,
  127.               gint32 *drawable_ID)
  128. {  
  129.   gimp_image_convert_grayscale (image_ID);
  130. }
  131.  
  132. static void
  133. export_convert_indexed (gint32  image_ID,
  134.             gint32 *drawable_ID)
  135. {  
  136.   gint32 nlayers;
  137.   
  138.   /* check alpha */
  139.   g_free (gimp_image_get_layers (image_ID, &nlayers));
  140.   if (nlayers > 1 || gimp_drawable_has_alpha (*drawable_ID))
  141.     gimp_image_convert_indexed (image_ID, GIMP_FS_DITHER, GIMP_MAKE_PALETTE, 255, FALSE, FALSE, "");
  142.   else
  143.     gimp_image_convert_indexed (image_ID, GIMP_FS_DITHER, GIMP_MAKE_PALETTE, 256, FALSE, FALSE, ""); 
  144. }
  145.  
  146. static void
  147. export_add_alpha (gint32  image_ID,
  148.           gint32 *drawable_ID)
  149. {  
  150.   gint32  nlayers;
  151.   gint32  i;
  152.   gint32 *layers;
  153.  
  154.   layers = gimp_image_get_layers (image_ID, &nlayers);
  155.   for (i = 0; i < nlayers; i++)
  156.     {
  157.       if (!gimp_drawable_has_alpha (layers[i]))
  158.     gimp_layer_add_alpha (layers[i]);
  159.     }
  160.   g_free (layers);  
  161. }
  162.  
  163.  
  164. /* a set of predefined actions */
  165.  
  166. static ExportAction export_action_merge =
  167. {
  168.   export_merge,
  169.   NULL,
  170.   N_("can't handle layers"),
  171.   { N_("Merge Visible Layers"), NULL },
  172.   0
  173. };
  174.  
  175. static ExportAction export_action_merge_single =
  176. {
  177.   export_merge,
  178.   NULL,
  179.   N_("can't handle layer offsets, size or opacity"),
  180.   { N_("Merge Visible Layers"), NULL },
  181.   0
  182. };
  183.  
  184. static ExportAction export_action_animate_or_merge =
  185. {
  186.   export_merge,
  187.   NULL,
  188.   N_("can only handle layers as animation frames"),
  189.   { N_("Merge Visible Layers"), N_("Save as Animation")},
  190.   0
  191. };
  192.  
  193. static ExportAction export_action_animate_or_flatten =
  194. {
  195.   export_flatten,
  196.   NULL,
  197.   N_("can only handle layers as animation frames"),
  198.   { N_("Flatten Image"), N_("Save as Animation") },
  199.   0
  200. };
  201.  
  202. static ExportAction export_action_merge_flat =
  203. {
  204.   export_flatten,
  205.   NULL,
  206.   N_("can't handle layers"),
  207.   { N_("Flatten Image"), NULL },
  208.   0
  209. };
  210.  
  211. static ExportAction export_action_flatten =
  212. {
  213.   export_flatten,
  214.   NULL,
  215.   N_("can't handle transparency"),
  216.   { N_("Flatten Image"), NULL },
  217.   0
  218. };
  219.  
  220. static ExportAction export_action_convert_rgb =
  221. {
  222.   export_convert_rgb,
  223.   NULL,
  224.   N_("can only handle RGB images"),
  225.   { N_("Convert to RGB"), NULL },
  226.   0
  227. };
  228.  
  229. static ExportAction export_action_convert_grayscale =
  230. {
  231.   export_convert_grayscale,
  232.   NULL,
  233.   N_("can only handle grayscale images"),
  234.   { N_("Convert to Grayscale"), NULL },
  235.   0
  236. };
  237.  
  238. static ExportAction export_action_convert_indexed =
  239. {
  240.   export_convert_indexed,
  241.   NULL,
  242.   N_("can only handle indexed images"),
  243.   { N_("Convert to Indexed using default settings\n"
  244.        "(Do it manually to tune the result)"), NULL },
  245.   0
  246. };
  247.  
  248. static ExportAction export_action_convert_rgb_or_grayscale =
  249. {
  250.   export_convert_rgb,
  251.   export_convert_grayscale,
  252.   N_("can only handle RGB or grayscale images"),
  253.   { N_("Convert to RGB"), N_("Convert to Grayscale")},
  254.   0
  255. };
  256.  
  257. static ExportAction export_action_convert_rgb_or_indexed =
  258. {
  259.   export_convert_rgb,
  260.   export_convert_indexed,
  261.   N_("can only handle RGB or indexed images"),
  262.   { N_("Convert to RGB"), N_("Convert to Indexed using default settings\n"
  263.                  "(Do it manually to tune the result)")},
  264.   0
  265. };
  266.  
  267. static ExportAction export_action_convert_indexed_or_grayscale =
  268. {
  269.   export_convert_indexed,
  270.   export_convert_grayscale,
  271.   N_("can only handle grayscale or indexed images"),
  272.   { N_("Convert to Indexed using default settings\n"
  273.        "(Do it manually to tune the result)"), 
  274.     N_("Convert to Grayscale") },
  275.   0
  276. };
  277.  
  278. static ExportAction export_action_add_alpha =
  279. {
  280.   export_add_alpha,
  281.   NULL,
  282.   N_("needs an alpha channel"),
  283.   { N_("Add Alpha Channel"), NULL},
  284.   0
  285. };
  286.  
  287.  
  288. /* dialog functions */
  289.  
  290. static GtkWidget            *dialog = NULL;
  291. static GimpExportReturnType  dialog_return = GIMP_EXPORT_CANCEL;
  292.  
  293. static void
  294. export_export_callback (GtkWidget *widget,
  295.             gpointer   data)
  296. {
  297.   gtk_widget_destroy (dialog);
  298.   dialog_return = GIMP_EXPORT_EXPORT;
  299. }
  300.  
  301. static void
  302. export_confirm_callback (GtkWidget *widget,
  303.              gpointer   data)
  304. {
  305.   gtk_widget_destroy (dialog);
  306.   dialog_return = GIMP_EXPORT_EXPORT;
  307. }
  308.  
  309. static void
  310. export_skip_callback (GtkWidget *widget,
  311.               gpointer   data)
  312. {
  313.   gtk_widget_destroy (dialog);
  314.   dialog_return = GIMP_EXPORT_IGNORE;
  315. }
  316.  
  317. static void
  318. export_cancel_callback (GtkWidget *widget,
  319.             gpointer   data)
  320. {
  321.   dialog_return = GIMP_EXPORT_CANCEL;
  322.   dialog = NULL;
  323.   gtk_main_quit ();
  324. }
  325.  
  326. static void
  327. export_toggle_callback (GtkWidget *widget,
  328.             gpointer   data)
  329. {
  330.   gint *choice = (gint*)data;
  331.   
  332.   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
  333.     *choice = 0;
  334.   else
  335.     *choice = 1;
  336. }
  337.  
  338. static gint
  339. confirm_save_dialog (const gchar *saving_what,
  340.              const gchar *format_name)
  341. {
  342.   GtkWidget    *vbox;
  343.   GtkWidget    *label;
  344.   gchar        *text;
  345.  
  346.   dialog_return = GIMP_EXPORT_CANCEL;
  347.   g_return_val_if_fail (saving_what != NULL && format_name != NULL, dialog_return);
  348.  
  349.   /*
  350.    *  Plug-ins must have called gtk_init () before calling gimp_export ().
  351.    *  Otherwise bad things will happen now!!
  352.    */
  353.  
  354.   /* the dialog */
  355.  
  356.   dialog = gimp_dialog_new (_("Confirm Save"), "confirm_save",
  357.                 gimp_standard_help_func, "dialogs/confirm_save.html",
  358.                 GTK_WIN_POS_MOUSE,
  359.                 FALSE, FALSE, FALSE,
  360.                 _("Confirm"), export_confirm_callback,
  361.                 NULL, NULL, NULL, TRUE, FALSE,
  362.                 _("Cancel"), gtk_widget_destroy,
  363.                 NULL, 1, NULL, FALSE, TRUE,
  364.  
  365.                 NULL);
  366.  
  367.   gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
  368.               GTK_SIGNAL_FUNC (export_cancel_callback),
  369.               NULL);
  370.  
  371.   vbox = gtk_vbox_new (FALSE, 6);
  372.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
  373.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
  374.   gtk_widget_show (vbox);
  375.  
  376.   text = g_strdup_printf (_("You are about to save %s as %s.\n"
  377.                 "This will not save the visible layers."),
  378.               saving_what, format_name);
  379.   label = gtk_label_new (text);
  380.   g_free (text);
  381.   gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
  382.   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  383.   gtk_widget_show (label);
  384.  
  385.   gtk_widget_show (dialog);
  386.   gtk_main ();
  387.  
  388.   return dialog_return;
  389. }
  390.  
  391. static gint
  392. export_dialog (GSList      *actions,
  393.            const gchar *format_name)
  394. {
  395.   GtkWidget    *frame;
  396.   GtkWidget    *vbox;
  397.   GtkWidget    *hbox;
  398.   GtkWidget    *button;
  399.   GtkWidget    *label;
  400.   GSList       *list;
  401.   gchar        *text;
  402.   ExportAction *action;
  403.  
  404.   dialog_return = GIMP_EXPORT_CANCEL;
  405.   g_return_val_if_fail (actions != NULL && format_name != NULL, dialog_return);
  406.  
  407.   /*
  408.    *  Plug-ins must have called gtk_init () before calling gimp_export ().
  409.    *  Otherwise bad things will happen now!!
  410.    */
  411.  
  412.   /* the dialog */
  413.  
  414.   dialog = gimp_dialog_new (_("Export File"), "export_file",
  415.                 gimp_standard_help_func, "dialogs/export_file.html",
  416.                 GTK_WIN_POS_MOUSE,
  417.                 FALSE, FALSE, FALSE,
  418.  
  419.                 _("Export"), export_export_callback,
  420.                 NULL, NULL, NULL, TRUE, FALSE,
  421.                 _("Ignore"), export_skip_callback,
  422.                 NULL, NULL, NULL, FALSE, FALSE,
  423.                 _("Cancel"), gtk_widget_destroy,
  424.                 NULL, 1, NULL, FALSE, TRUE,
  425.  
  426.                 NULL);
  427.  
  428.   gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
  429.               GTK_SIGNAL_FUNC (export_cancel_callback),
  430.               NULL);
  431.  
  432.   /* the headline */
  433.   vbox = gtk_vbox_new (FALSE, 6);
  434.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
  435.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
  436.   gtk_widget_show (vbox);
  437.  
  438.   label = gtk_label_new (_("Your image should be exported before it "
  439.                "can be saved for the following reasons:"));
  440.   gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
  441.   gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
  442.   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  443.   gtk_widget_show (label);
  444.  
  445.   for (list = actions; list; list = list->next)
  446.     {
  447.       action = (ExportAction *) (list->data);
  448.  
  449.       text = g_strdup_printf ("%s %s", format_name, gettext (action->reason));
  450.       frame = gtk_frame_new (text);
  451.       g_free (text);
  452.       gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  453.  
  454.       hbox = gtk_hbox_new (FALSE, 4);
  455.       gtk_container_add (GTK_CONTAINER (frame), hbox);
  456.       gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
  457.  
  458.       if (action->possibilities[0] && action->possibilities[1])
  459.     {
  460.       GSList *radio_group = NULL;
  461.  
  462.       button = gtk_radio_button_new_with_label (radio_group, 
  463.                             gettext (action->possibilities[0]));
  464.       gtk_label_set_justify (GTK_LABEL (GTK_BIN (button)->child), GTK_JUSTIFY_LEFT);
  465.       radio_group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
  466.       gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  467.       gtk_signal_connect (GTK_OBJECT (button), "toggled",
  468.                   GTK_SIGNAL_FUNC (export_toggle_callback),
  469.                   &action->choice);
  470.       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
  471.       gtk_widget_show (button);
  472.  
  473.       button = gtk_radio_button_new_with_label (radio_group, 
  474.                             gettext (action->possibilities[1]));
  475.       gtk_label_set_justify (GTK_LABEL (GTK_BIN (button)->child), GTK_JUSTIFY_LEFT);
  476.       radio_group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
  477.       gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  478.       gtk_widget_show (button);
  479.     } 
  480.       else if (action->possibilities[0])
  481.     {
  482.       label = gtk_label_new (gettext (action->possibilities[0]));
  483.       gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
  484.       gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2);
  485.       gtk_widget_show (label);
  486.       action->choice = 0;
  487.     }
  488.       else if (action->possibilities[1])
  489.     {
  490.       label = gtk_label_new (gettext (action->possibilities[1]));
  491.       gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
  492.       gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2);
  493.       gtk_widget_show (label);
  494.       action->choice = 1;
  495.     }      
  496.       gtk_widget_show (hbox);
  497.       gtk_widget_show (frame);
  498.     }
  499.  
  500.   /* the footline */
  501.   label = gtk_label_new (_("The export conversion won't modify your original image."));
  502.   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  503.   gtk_widget_show (label);
  504.  
  505.   gtk_widget_show (dialog);
  506.   gtk_main ();
  507.  
  508.   return dialog_return;
  509. }
  510.  
  511. /**
  512.  * gimp_export_image:
  513.  * @image_ID: Pointer to the image_ID.
  514.  * @drawable_ID: Pointer to the drawable_ID.
  515.  * @format_name: The (short) name of the image_format (e.g. JPEG or GIF).
  516.  * @capabilities: What can the image_format do?
  517.  *
  518.  * Takes an image and a drawable to be saved together with a
  519.  * description of the capabilities of the image_format. If the
  520.  * type of image doesn't match the capabilities of the format
  521.  * a dialog is opened that informs the user that the image has
  522.  * to be exported and offers to do the necessary conversions.
  523.  *
  524.  * If the user chooses to export the image, a copy is created.
  525.  * This copy is then converted, the image_ID and drawable_ID
  526.  * are changed to point to the new image and the procedure returns
  527.  * GIMP_EXPORT_EXPORT. The save_plugin has to take care of deleting the
  528.  * created image using gimp_image_delete() when it has saved it.
  529.  *
  530.  * If the user chooses to Ignore the export problem, the image_ID
  531.  * and drawable_ID is not altered, GIMP_EXPORT_IGNORE is returned and 
  532.  * the save_plugin should try to save the original image. If the 
  533.  * user chooses Cancel, GIMP_EXPORT_CANCEL is returned and the 
  534.  * save_plugin should quit itself with status #STATUS_CANCEL.
  535.  *
  536.  * Returns: An enum of #GimpExportReturnType describing the user_action.
  537.  **/
  538. GimpExportReturnType
  539. gimp_export_image (gint32                 *image_ID,
  540.            gint32                 *drawable_ID,
  541.            const gchar            *format_name,
  542.            GimpExportCapabilities  capabilities)
  543. {
  544.   GSList *actions = NULL;
  545.   GSList *list;
  546.   GimpImageBaseType type;
  547.   gint32  i;
  548.   gint32  nlayers;
  549.   gint32* layers;
  550.   gint    offset_x;
  551.   gint    offset_y;
  552.   gboolean added_flatten = FALSE;
  553.   gboolean background_has_alpha = TRUE;
  554.   ExportAction *action;
  555.  
  556.   g_return_val_if_fail (*image_ID > -1 && *drawable_ID > -1, FALSE);
  557.  
  558.   /* do some sanity checks */
  559.   if (capabilities & GIMP_EXPORT_NEEDS_ALPHA)
  560.     capabilities |= GIMP_EXPORT_CAN_HANDLE_ALPHA ;
  561.   if (capabilities & GIMP_EXPORT_CAN_HANDLE_LAYERS_AS_ANIMATION)
  562.     capabilities |= GIMP_EXPORT_CAN_HANDLE_LAYERS;
  563.  
  564.   /* ask for confirmation if the user is not saving a layer (see bug #51114) */
  565.   if (!gimp_drawable_is_layer (*drawable_ID)
  566.       && !(capabilities & GIMP_EXPORT_CAN_HANDLE_LAYERS))
  567.     {
  568.       if (gimp_drawable_is_layer_mask (*drawable_ID))
  569.     dialog_return = confirm_save_dialog (_("a layer mask"),    format_name);
  570.       else if (gimp_drawable_is_channel (*drawable_ID))
  571.     dialog_return = confirm_save_dialog (_("a channel (saved selection)"),
  572.                          format_name);
  573.       else
  574.     ; /* this should not happen */
  575.  
  576.       /* cancel - the user can then select an appropriate layer to save */
  577.       if (dialog_return == GIMP_EXPORT_CANCEL)
  578.     return GIMP_EXPORT_CANCEL;
  579.     }
  580.  
  581.   /* check alpha */
  582.   layers = gimp_image_get_layers (*image_ID, &nlayers);
  583.   for (i = 0; i < nlayers; i++)
  584.     {
  585.       if (gimp_drawable_has_alpha (layers[i]))
  586.     {
  587.  
  588.       if ( !(capabilities & GIMP_EXPORT_CAN_HANDLE_ALPHA ) )
  589.         {
  590.           actions = g_slist_prepend (actions, &export_action_flatten);
  591.           added_flatten = TRUE;
  592.           break;
  593.         }
  594.     }
  595.       else 
  596.     {
  597.           /* If this is the last layer, it's visible and has no alpha
  598.              channel, then the image has a "flat" background */
  599.             if (i == nlayers - 1 && gimp_layer_get_visible (layers[i])) 
  600.         background_has_alpha = FALSE;
  601.  
  602.       if (capabilities & GIMP_EXPORT_NEEDS_ALPHA)
  603.         {
  604.           actions = g_slist_prepend (actions, &export_action_add_alpha);
  605.           break;
  606.         }
  607.     }
  608.     }
  609.   g_free (layers);
  610.  
  611.   /* check if layer size != canvas size, opacity != 100%, or offsets != 0 */
  612.   if (!added_flatten && nlayers == 1 && gimp_drawable_is_layer (*drawable_ID)
  613.       && !(capabilities & GIMP_EXPORT_CAN_HANDLE_LAYERS))
  614.     {
  615.       gimp_drawable_offsets (*drawable_ID, &offset_x, &offset_y);
  616.       if ((gimp_layer_get_opacity (*drawable_ID) < 100.0)
  617.       || (gimp_image_width (*image_ID)
  618.           != gimp_drawable_width (*drawable_ID))
  619.       || (gimp_image_height (*image_ID)
  620.           != gimp_drawable_height (*drawable_ID))
  621.       || offset_x || offset_y)
  622.     {
  623.       if (capabilities & GIMP_EXPORT_CAN_HANDLE_ALPHA)
  624.         actions = g_slist_prepend (actions, &export_action_merge_single);
  625.       else
  626.         {
  627.           actions = g_slist_prepend (actions, &export_action_flatten);
  628.           added_flatten = TRUE;
  629.         }
  630.     }
  631.     }
  632.   /* check multiple layers */
  633.   else if (!added_flatten && nlayers > 1)
  634.     {
  635.       if (capabilities & GIMP_EXPORT_CAN_HANDLE_LAYERS_AS_ANIMATION)
  636.     {
  637.       if (background_has_alpha || capabilities & GIMP_EXPORT_NEEDS_ALPHA)
  638.         actions = g_slist_prepend (actions, &export_action_animate_or_merge);
  639.       else
  640.         actions = g_slist_prepend (actions, &export_action_animate_or_flatten);
  641.     }
  642.       else if ( !(capabilities & GIMP_EXPORT_CAN_HANDLE_LAYERS))
  643.     {
  644.       if (background_has_alpha || capabilities & GIMP_EXPORT_NEEDS_ALPHA)
  645.         actions = g_slist_prepend (actions, &export_action_merge);
  646.       else
  647.         actions = g_slist_prepend (actions, &export_action_merge_flat);
  648.     }
  649.     }
  650.  
  651.   /* check the image type */      
  652.   type = gimp_image_base_type (*image_ID);
  653.   switch (type)
  654.     {
  655.     case GIMP_RGB:
  656.        if ( !(capabilities & GIMP_EXPORT_CAN_HANDLE_RGB) )
  657.     {
  658.       if ((capabilities & GIMP_EXPORT_CAN_HANDLE_INDEXED) && (capabilities & GIMP_EXPORT_CAN_HANDLE_GRAY))
  659.         actions = g_slist_prepend (actions, &export_action_convert_indexed_or_grayscale);
  660.       else if (capabilities & GIMP_EXPORT_CAN_HANDLE_INDEXED)
  661.         actions = g_slist_prepend (actions, &export_action_convert_indexed);
  662.       else if (capabilities & GIMP_EXPORT_CAN_HANDLE_GRAY)
  663.         actions = g_slist_prepend (actions, &export_action_convert_grayscale);
  664.     }
  665.       break;
  666.     case GIMP_GRAY:
  667.       if ( !(capabilities & GIMP_EXPORT_CAN_HANDLE_GRAY) )
  668.     {
  669.       if ((capabilities & GIMP_EXPORT_CAN_HANDLE_RGB) && (capabilities & GIMP_EXPORT_CAN_HANDLE_INDEXED))
  670.         actions = g_slist_prepend (actions, &export_action_convert_rgb_or_indexed);
  671.       else if (capabilities & GIMP_EXPORT_CAN_HANDLE_RGB)
  672.         actions = g_slist_prepend (actions, &export_action_convert_rgb);
  673.       else if (capabilities & GIMP_EXPORT_CAN_HANDLE_INDEXED)
  674.         actions = g_slist_prepend (actions, &export_action_convert_indexed);
  675.     }
  676.       break;
  677.     case GIMP_INDEXED:
  678.        if ( !(capabilities & GIMP_EXPORT_CAN_HANDLE_INDEXED) )
  679.     {
  680.       if ((capabilities & GIMP_EXPORT_CAN_HANDLE_RGB) && (capabilities & GIMP_EXPORT_CAN_HANDLE_GRAY))
  681.         actions = g_slist_prepend (actions, &export_action_convert_rgb_or_grayscale);
  682.       else if (capabilities & GIMP_EXPORT_CAN_HANDLE_RGB)
  683.         actions = g_slist_prepend (actions, &export_action_convert_rgb);
  684.       else if (capabilities & GIMP_EXPORT_CAN_HANDLE_GRAY)
  685.         actions = g_slist_prepend (actions, &export_action_convert_grayscale);
  686.     }
  687.       break;
  688.     }
  689.   
  690.   if (actions)
  691.     {
  692.       actions = g_slist_reverse (actions);
  693.       dialog_return = export_dialog (actions, format_name);
  694.     }
  695.   else
  696.     dialog_return = GIMP_EXPORT_IGNORE;
  697.  
  698.   if (dialog_return == GIMP_EXPORT_EXPORT)
  699.     {
  700.       *image_ID = gimp_image_duplicate (*image_ID);
  701.       *drawable_ID = gimp_image_get_active_layer (*image_ID);
  702.       gimp_image_undo_disable (*image_ID);
  703.       for (list = actions; list; list = list->next)
  704.     {
  705.       action = (ExportAction*)(list->data);
  706.       if (action->choice == 0 && action->default_action)  
  707.         action->default_action (*image_ID, drawable_ID);
  708.       else if (action->choice == 1 && action->alt_action)
  709.         action->alt_action (*image_ID, drawable_ID);
  710.     }
  711.     }
  712.   g_slist_free (actions);
  713.  
  714.   return dialog_return;
  715. }
  716.